////////////////////////////////////////////////////////////////////////////////
// uftpd is a userspace ftp daemon using qt for network gui and file io.
// Copyright (C) 2008 Tobias Wich
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
////////////////////////////////////////////////////////////////////////////////

///
/// \file ftp_commands.H
/// \brief FTP types and classes to use this stuff.
///

#ifndef __FTP_COMMANDS_H__
#define __FTP_COMMANDS_H__

#include <string>
#include <sstream>

using namespace std;

namespace uftpd {

  ///
  /// \enum ReplyCodeE
  /// \brief Definition of all RFC0959 reply codes as on page 42 and 43
  ///
  enum ReplyCodeE { FTP_RESTART_MARKER = 110,
		    FTP_READY_IN_N_MIN = 120,
		    FTP_DATA_OPEN_TRANS_STARTING = 125,
		    FTP_FILE_STAT_OK_START_CON = 150,
		    FTP_CMD_OK = 200,
		    FTP_CMD_NOT_IMPLEMENTED = 202,
		    FTP_SYS_STATUS = 211,
		    FTP_DIR_STATUS = 212,
		    FTP_FILE_STATUS = 213,
		    FTP_HELP = 214,
		    FTP_SYS_TYPE = 215,
		    FTP_READY = 220,
		    FTP_CLOSING = 221,
		    FTP_DATA_OPEN_NO_TRANSFER = 225,
		    FTP_CLOSING_DATA = 226,
		    FTP_ENTER_PASV = 227,
		    FTP_LOGGED_IN = 230,
		    FTP_FILE_ACTION_OK = 250,
		    FTP_PATH_CREATED = 257,
		    FTP_USER_OK = 331,
		    FTP_NEED_ACCOUNT_FOR_LOGIN = 332,
		    FTP_REQUESTED_FILE_ACTION_PENDING = 350,
		    FTP_SERVICE_NA = 421,
		    FTP_CANT_OPEN_DATA_CON = 425,
		    FTP_CON_CLOSED = 426,
		    FTP_FILE_BUSY = 450,
		    FTP_ACTION_ABORT_LOCAL_ERROR = 451,
		    FTP_ACTION_NOT_TAKEN_NO_SPACE = 452,
		    FTP_SYNTAX_ERROR = 500,
		    FTP_SYNTAX_PARAM_ERROR = 501,
		    FTP_COMMAND_NOT_IMPLEMENTED = 502,
		    FTP_BAD_SEQUENCE = 503,
		    FTP_COMMAND_NOT_IMPLEMENTED_FOR_PARAM = 504,
		    FTP_NOT_LOGGED = 530,
		    FTP_NEED_ACCOUNT_FOR_FILETRANS = 532,
		    FTP_NO_SUCH_FILE = 550,
		    FTP_ACTION_ABORT_UNKN_PAGE_TYPE = 551,
		    FTP_ACTION_ABORT_NO_SPACE = 552,
		    FTP_ACTION_NOT_TAKEN_INVALID_FNAME = 553,
  };

  ///
  /// \class ReplyCodeT
  /// \brief ReplyCodeT represents the reply code and its description.
  ///
  class ReplyCodeT {
  private:
    ReplyCodeE mCode; ///< Reply code from the FTP RFC.
    string mDescription; ///< Textual description of the reply code.

    ReplyCodeT() { }

  public:

    ///
    /// \fn ReplyCodeT
    /// \param code Reply code of the new message.
    /// \brief Construct ReplyCodeT with default description.
    ///
    ReplyCodeT(ReplyCodeE code) : mCode(code) {
      string & d = mDescription;
      switch (code) {
      case FTP_RESTART_MARKER:
	d = "Restart marker reply."; break;
      case FTP_READY:
	d = "Service ready."; break;
      case FTP_USER_OK:
	d = "User name ok, need password."; break;
      case FTP_SERVICE_NA:
	d = "Service not available, closing connection."; break;
      default:
	break;
      }
    }

    ///
    /// \fn ReplyCodeT
    /// \param code Reply code of the new message.
    /// \param description User specific reply code description
    /// \brief Construct ReplyCodeT with a user defined reply code description.
    ///
    ReplyCodeT(ReplyCodeE code, string description) : mCode(code), mDescription(description) { }

    ///
    /// \fn code
    /// \return FTP reply code.
    ///
    inline ReplyCodeE code() const {
      return mCode;
    }

    ///
    /// \fn description
    /// \return Description of the reply code.
    ///
    inline string description() const {
      return mDescription;
    }

    ///
    /// \fn msg
    /// \return String representation of the reply message ready for delivery.
    ///
    inline string msg() const {
      stringstream stream;
      stream << mCode << " " << mDescription << '\r' << '\n';
      return stream.str();
    }

    inline ReplyCodeT & operator=(const ReplyCodeT & newCode) {
      this->mCode = newCode.mCode;
      this->mDescription = newCode.mDescription;
      return *this;
    }

    inline bool operator==(const ReplyCodeT & x) {
      return x.code() == code();
    }

  };

}

#endif
